using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Schema;
using OpenComposite.Repository.Properties;
using OpenComposite.EII.Repository;
using OpenComposite.Mapper;

namespace OpenComposite.Mapper
{
	public partial class FormMapping : Form
	{
		#region Initialization
		public FormMapping()
		{
			//SemanticParserService.Start();
			InitializeComponent();

			//xsltEditor.Document.HeaderText = "<?xml version=\"1.0\" encoding=\"utf-16\"?>";

			xsltEditor.SetHighlighting("XML");

			tabCtrlMapping.TabPages.Remove(tabCodeMapping);

			this.DialogResult = DialogResult.Cancel;
		}
		#endregion

		#region Public Members

		#region Properties
		public MapperSettings MapperSettings
		{
			get { return mapperCtrl.MapperSettings; }
		}
		public bool UseCodeMapping
		{
			get { return codeMapperControl1.UseCodeMapping; }
			set
			{
				codeMapperControl1.UseCodeMapping = value;
				if ( value ) tabCtrlMapping.SelectedTab = tabCodeMapping;
			}
		}
		public string HeaderText
		{
			get { return codeMapperControl1.HeaderText; }
		}
		#endregion

		#region Methods
		public void InitializeMapper(XmlSchema sourceSchema, XmlSchema targetSchema,
			string xslt, string mappingxml,
			string codeMapping)
		{
			_xsdSource = sourceSchema;
			_xsdTarget = targetSchema;
			_xsetSource = null;
			_xsetTarget = null;
			mapperCtrl.InitializeMapper(sourceSchema, targetSchema, mappingxml);
			if ( MapperSettings.IsCustomXSLT ) {
				XsltDocument xd = new XsltDocument();
				if ( xslt != null ) {
					xd.LoadXml(xslt);
				}
				setXSLTTextbox(xd);
				tabCtrlMapping.SelectedTab = tabXSLTCode;
			}

			if ( _startDoc == null ) {
				string mapping;
				_startDoc = GetMapping(out mapping);
			}
		}
		public void InitializeMapper(XmlSchema sourceSchema, XmlSchemaSet sourceSet,
			XmlSchema targetSchema, XmlSchemaSet targetSet, string xslt, string mappingxml)
		{
			_xsdSource = sourceSchema;
			_xsdTarget = targetSchema;
			_xsetSource = sourceSet;
			_xsetTarget = targetSet;
			mapperCtrl.InitializeMapper(sourceSchema, sourceSet, targetSchema, targetSet, mappingxml);
			if ( MapperSettings.IsCustomXSLT ) {
				XsltDocument xd = new XsltDocument();
				xd.LoadXml(xslt);
				setXSLTTextbox(xd);
				tabCtrlMapping.SelectedTab = tabXSLTCode;
			}

			XmlSchemaSet schemaSet = new XmlSchemaSet();
			try {
				if ( targetSet != null ) schemaSet.Add(targetSet);
				if ( sourceSet != null ) schemaSet.Add(sourceSet);
			} catch { }

			if ( _startDoc == null ) {
				string mapping;
				_startDoc = GetMapping(out mapping);
			}
		}

		public XsltDocument GetMapping(out string mappingXml)
		{
			XsltDocument xslt;
			xslt = mapperCtrl.GenerateXslt(out mappingXml);
			if ( MapperSettings.IsCustomXSLT ) {
				if ( !getXsltDocFormXsltTextbox(out xslt) ) return null;
			}
			return xslt;
		}
		public void SetMappingText(string value, LogicalActivity logAct, bool isInput)
		{
			if ( !tabCtrlMapping.TabPages.Contains(tabCodeMapping) ) {
				tabCtrlMapping.TabPages.Add(tabCodeMapping);
			}
			codeMapperControl1.SetMappingText(value, logAct, isInput);
		}
		public void SetMappingText(ISupportLogicalPhysicalMapping lwm, bool isInput)
		{
			if ( lwm == null ) return;
			if ( !tabCtrlMapping.TabPages.Contains(tabCodeMapping) ) {
				tabCtrlMapping.TabPages.Add(tabCodeMapping);
			}
			codeMapperControl1.SetMappingText(lwm, isInput);
		}
		public string GetCodeMapping()
		{
			if ( !UseCodeMapping ) return null;
			return codeMapperControl1.MappingText;
		}
		#endregion

		#endregion

		#region Private Members

		#region Variables
		private XmlSchema _xsdSource;
		private XmlSchema _xsdTarget;
		private XmlSchemaSet _xsetSource;
		private XmlSchemaSet _xsetTarget;
		private XsltDocument _startDoc = null;
		#endregion

		#region Methods
		private bool getXsltDocFormXsltTextbox(out XsltDocument xsltDoc)
		{
			xsltDoc = new XsltDocument();
			try {
				xsltDoc.LoadXml(xsltEditor.Text);
			} catch ( XmlException xmlex ) {
				MessageBox.Show(xmlex.Message, "XSLT Code", MessageBoxButtons.OK, MessageBoxIcon.Error);
				// TODO: select the line and position where the error occurs
				return false;
			} catch ( Exception ex ) {
				MessageBox.Show(ex.Message, "XSLT Code", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return false;
			}
			return true;
		}
		#endregion

		#region Event Handler
		private void tsbtnSave_Click(object sender, EventArgs e)
		{
			if ( MapperSettings.IsCustomXSLT ) {
				XsltDocument xslt;
				if ( !getXsltDocFormXsltTextbox(out xslt) ) return;
			}
			this.DialogResult = DialogResult.OK;
			this.Close();
		}
		private void FormMapping_Load(object sender, EventArgs e)
		{
		}

		private void tsbtnShowXSLT_Click(object sender, EventArgs e)
		{
			XsltDocument xd = null;
			if ( MapperSettings.IsCustomXSLT ) {
				if ( !getXsltDocFormXsltTextbox(out xd) ) return;
			} else {
				string map;
				xd = mapperCtrl.GenerateXslt(out map);
			}
			formXmlViewer viewer = new formXmlViewer();
			viewer.XmlDocument = xd;
			viewer.ShowDialog();
		}

		private void FormMapping_FormClosing(object sender, FormClosingEventArgs e)
		{
			if ( this.DialogResult != DialogResult.OK ) {
				string map;
				XsltDocument newDoc = GetMapping(out map);
				if ( ( newDoc != null && _startDoc != null ) && newDoc.OuterXml != _startDoc.OuterXml ) {
					DialogResult result = MessageBox.Show(Resources.msgMapperClosing, this.Text, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
					if ( result == DialogResult.Yes ) {
						if ( MapperSettings.IsCustomXSLT ) {
							XsltDocument xslt;
							if ( !getXsltDocFormXsltTextbox(out xslt) ) {
								e.Cancel = true;
								return;
							}
						}
						this.DialogResult = DialogResult.OK;
					} else if ( result == DialogResult.No ) {
						this.DialogResult = DialogResult.Cancel;
					} else {
						e.Cancel = true;
					}
				} else {
					this.DialogResult = DialogResult.Cancel;
				}
			}
		}

		private void tabCtrlMapping_SelectedIndexChanged(object sender, EventArgs e)
		{
			if ( tabCtrlMapping.SelectedTab == tabMapper ) {

			} else if ( tabCtrlMapping.SelectedTab == tabXSLTCode ) {

			} else if ( tabCtrlMapping.SelectedTab == tabExternal ) {
			}
		}

		private void tabCtrlMapping_Selecting(object sender, TabControlCancelEventArgs e)
		{
			if ( e.TabPage == tabMapper ) {
				if ( MapperSettings.IsCustomXSLT ) {
					DialogResult result = MessageBox.Show(
						string.Format("If you switch back to the \"XSLT Mapper\" tab, " +
							"your custom XSLT code will be overwritten.{0}{0}" +
							"Do you want to continue?", Environment.NewLine),
						"Generate XSLT", MessageBoxButtons.YesNo, MessageBoxIcon.Stop);
					if ( result != DialogResult.Yes ) {
						e.Cancel = true;
					} else {
						MapperSettings.IsCustomXSLT = false;
					}
				}
			} else if ( e.TabPage == tabXSLTCode ) {
				if ( !MapperSettings.IsCustomXSLT ) {
					string map;
					XsltDocument xd = mapperCtrl.GenerateXslt(out map);
					setXSLTTextbox(xd);
				}
			} else if ( e.TabPage == tabExternal ) {
				if ( !Directory.Exists(txtPath.Text) ) {
					txtPath.Text = Path.Combine(Path.GetTempPath(), "Mapping");
				}
			}
		}

		private void setXSLTTextbox(XsltDocument xd)
		{
			if ( xd != null ) {
				XmlWriterSettings settings = new XmlWriterSettings();
				settings.Indent = true;
				settings.IndentChars = "\t";
				settings.NewLineChars = Environment.NewLine;
				settings.NewLineOnAttributes = false;
				settings.OmitXmlDeclaration = true;
				StringBuilder sb = new StringBuilder();
				try {
					using ( XmlWriter xw = XmlWriter.Create(sb, settings) ) {
						xd.WriteTo(xw);
						xw.Flush();
					}
				} catch ( Exception ex ) {
					MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
				xsltEditor.Text = sb.ToString();
			} else {
				xsltEditor.Text = "";
			}
		}

		private void tabCtrlMapping_Deselecting(object sender, TabControlCancelEventArgs e)
		{
		}

		private void btnSelectPath_Click(object sender, EventArgs e)
		{
			FolderBrowserDialog dlg = new FolderBrowserDialog();
			dlg.Description = "Select a folder to export the source and target schemas and to import the XSLT file.";
			if ( Directory.Exists(txtPath.Text) ) {
				dlg.SelectedPath = txtPath.Text;
			}
			dlg.ShowNewFolderButton = true;
			if ( dlg.ShowDialog() == DialogResult.OK ) {
				txtPath.Text = dlg.SelectedPath;
			}
		}

		private void btnExport_Click(object sender, EventArgs e)
		{
			int i;
			string path = txtPath.Text;
			if ( !Directory.Exists(path) ) {
				Directory.CreateDirectory(path);
			}
			using ( StreamWriter sw = File.CreateText(Path.Combine(path, "Source.xsd")) ) {
				_xsdSource.Write(sw);
			}
			using ( StreamWriter sw = File.CreateText(Path.Combine(path, "Target.xsd")) ) {
				_xsdTarget.Write(sw);
			}
			if ( _xsetSource != null ) {
				i = 0;
				foreach ( XmlSchema xsd in _xsetSource.Schemas() ) {
					string nm = string.Format("source_additional{0}.xsd", i);
					using ( StreamWriter sw = File.CreateText(Path.Combine(path, nm)) ) {
						xsd.Write(sw);
					}
					i++;
				}
			}
			if ( _xsetTarget != null ) {
				i = 0;
				foreach ( XmlSchema xsd in _xsetTarget.Schemas() ) {
					string nm = string.Format("target_additional{0}.xsd", i);
					using ( StreamWriter sw = File.CreateText(Path.Combine(path, nm)) ) {
						xsd.Write(sw);
					}
					i++;
				}
			}
			System.Diagnostics.Process.Start(path);
		}

		private void btnImport_Click(object sender, EventArgs e)
		{
			string path = txtPath.Text;
			if ( !Directory.Exists(path) ) {
				MessageBox.Show("Invalid Import/Export Path. Please select an existing path.", "Import XSLT", MessageBoxButtons.OK, MessageBoxIcon.Error);
				btnSelectPath.PerformClick();
				return;
			}
			string xsltFileNm = null;
			string[] files = Directory.GetFiles(path, "*.xslt");
			if ( files == null || files.Length != 1 ) {
				OpenFileDialog dlg = new OpenFileDialog();
				dlg.CheckFileExists = true;
				dlg.CheckPathExists = true;
				dlg.DefaultExt = "xslt";
				dlg.Filter = "XSL Transform (*.xslt)|*.xslt|All Files (*.*)|*.*";
				dlg.FilterIndex = 0;
				dlg.InitialDirectory = path;
				dlg.Multiselect = false;
				dlg.Title = "Please select the XSL Transform file to import into the current mapping.";
				if ( dlg.ShowDialog() == DialogResult.OK ) {
					xsltFileNm = dlg.FileName;
				} else {
					return;
				}
			} else {
				xsltFileNm = files[0];
			}
			XsltDocument xd = new XsltDocument();
			try {
				xd.Load(xsltFileNm);
			} catch ( Exception ex ) {
				MessageBox.Show(
					string.Format("An error occured while importing the XSLT file:{0}{0}{1}",
						Environment.NewLine, ex.Message),
					"Import XSLT", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}
			setXSLTTextbox(xd);
			MapperSettings.IsCustomXSLT = true;
			MessageBox.Show(
				string.Format("XSL Transform file '{0}' imported successfully.", xsltFileNm),
				"Import XSLT", MessageBoxButtons.OK, MessageBoxIcon.Information);
		}

		#endregion

		private void txtXSLT_KeyPress(object sender, EventArgs e)
		{
			if ( !MapperSettings.IsCustomXSLT ) {
				MapperSettings.IsCustomXSLT = true;
			}
		}

		#endregion

	}
}